/**
 * @file    drv_gpio.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, GPIO抽象层
 * @version 1.01
 * @date    2025-07-02
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-02     yhy          the first version V1.00
 * 2025-07-11     yhy          1. 所有函数和变量名修改为snf_开头 V1.01
 *                             2. 增加了引脚初始电平配置项
 *                             3. 增加了GPIO的pin mode配置函数
 *
 */
#include "drv_gpio.h"

#include "gpio_drv.h"

#include <stddef.h>

/**
 * @brief GPIO引脚信息结构体 - 用于缓存计算结果
 *
 */
typedef struct
{
    GPIO_Type *port;  /*!< GPIO端口指针 */
    uint32_t   pin;   /*!< 端口内引脚编号 */
    bool       valid; /*!< 引脚是否有效 */
} snf_gpio_pin_info_t;

static result_e snf_drv_gpio_get_pin_info(uint32_t pin_num, snf_gpio_pin_info_t *pin_info);
static result_e snf_drv_gpio_validate_config(const snf_gpio_config_t *config);
static result_e snf_drv_gpio_pin_mode_handle(gpio_pin_config_t       *im_pin_config,
                                             const snf_gpio_config_t *user_pin_config);

/* 端口查找表 */
static GPIO_Type *const gpio_port_table[GPIO_PORT_MAX_COUNT] = { GPIOA, GPIOB, GPIOC, GPIOD, GPIOE };

/**
 * @brief 检查引脚编号是否有效
 *
 * @param pin_num   引脚编号
 * @return true     引脚编号有效
 * @return false    引脚编号无效
 */
inline static bool snf_drv_gpio_is_valid_pin_num(uint32_t pin_num) { return (pin_num < GPIO_MAX_PIN_NUM); }

/**
 * @brief 检查电平是否有效
 *
 * @param level     输入的电平
 * @return true     有效
 * @return false    无效
 */
inline static bool snf_drv_gpio_is_valid_level(snf_gpio_pin_level_e level)
{
    return (level <= DRV_GPIO_PIN_LEVEL_HIGH);
}

/**
 * @brief 初始化GPIO pin
 *
 * @param   gpio_config GPIO初始化参数结构体指针
 * @return  result_e    初始化结果, 返回RESULT_STATUS_OK表示成功, 其他值表示失败
 */
result_e snf_drv_gpio_init(const snf_gpio_config_t *gpio_config)
{
    result_e            status;
    snf_gpio_pin_info_t pin_info;

    /* 参数验证 */
    status = snf_drv_gpio_validate_config(gpio_config);
    if (status != RESULT_STATUS_OK) {
        return status;
    }

    /* 获取引脚信息 */
    status = snf_drv_gpio_get_pin_info(gpio_config->pin_num, &pin_info);
    if (status != RESULT_STATUS_OK) {
        return status;
    }

    /* 构建底层配置 */
    gpio_pin_config_t pin_config = {
        .base          = pin_info.port,
        .pin           = pin_info.pin,
        .mux           = GPIO_PIN_MUX_GPIO,
        .intConfig     = (gpio_pin_int_t)gpio_config->interrupt_config,
        .slewRate      = GPIO_PIN_SLEW_RATE_FAST,
        .driveStrength = GPIO_PIN_DRV_5MA,
        .initLevel     = (gpio_pin_level_t)gpio_config->init_level,
    };

    /* pin mode配置 */
    status = snf_drv_gpio_pin_mode_handle(&pin_config, gpio_config);
    if (status != RESULT_STATUS_OK) {
        return status;
    }

    /* 调用底层初始化 */
    GPIO_Init(1, &pin_config);

    return RESULT_STATUS_OK;
}

/**
 * @brief 设置GPIO引脚电平
 *
 * @param   pin_num     GPIO引脚编号, 通过GET_PIN_NUM宏获取
 * @param   level       要设置的GPIO引脚电平
 * @return  result_e    设置结果, RESULT_STATUS_OK为成功, 其他为失败
 */
result_e snf_drv_gpio_write_pin(uint32_t pin_num, snf_gpio_pin_level_e level)
{
    result_e            status;
    snf_gpio_pin_info_t pin_info;

    /* 参数验证 */
    if (!snf_drv_gpio_is_valid_level(level)) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 获取引脚信息 */
    status = snf_drv_gpio_get_pin_info(pin_num, &pin_info);
    if (status != RESULT_STATUS_OK) {
        return status;
    }

    /* 写入引脚电平 */
    GPIO_WritePin(pin_info.port, pin_info.pin, (gpio_pin_level_t)level);

    return RESULT_STATUS_OK;
}

/**
 * @brief 读取当前GPIO引脚电平
 *
 * @param   pin_num     GPIO引脚编号, 通过GET_PIN_NUM宏获取
 * @param   level       输出的引脚电平
 * @return  result_e    读取结果, RESULT_STATUS_OK为成功, 其他为失败
 */
result_e snf_drv_gpio_read_pin(uint32_t pin_num, snf_gpio_pin_level_e *level)
{
    result_e            status;
    snf_gpio_pin_info_t pin_info;

    /* 参数验证 */
    if (level == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 获取引脚信息 */
    status = snf_drv_gpio_get_pin_info(pin_num, &pin_info);
    if (status != RESULT_STATUS_OK) {
        return status;
    }

    /* 读取引脚电平 */
    *level = (snf_gpio_pin_level_e)GPIO_ReadPin(pin_info.port, pin_info.pin);

    return RESULT_STATUS_OK;
}

/**
 * @brief 设置引脚模式, 只适用于初始化完的PIN, 使用中途修改模式, 例如软件I2C的SDA引脚
 *
 * @param pin_num       GPIO引脚编号
 * @param mode          引脚模式
 * @return result_e     设置结果, RESULT_STATUS_OK为成功, 其他为失败
 */
result_e snf_drv_gpio_set_pin_mode(uint32_t pin_num, snf_gpio_pin_mode_e mode)
{
    if (mode > DRV_GPIO_PIN_MODE_INPUT_PULL_DOWN) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    uint32_t port_idx = pin_num / PORT_PIN_MAX_SIZE;
    uint32_t pin      = pin_num % PORT_PIN_MAX_SIZE;
    GPIO_SetPinMode(gpio_port_table[port_idx], pin, (gpio_pin_mode_t)mode);

    return RESULT_STATUS_OK;
}

/**
 * @brief 获取GPIO引脚信息
 *
 * @param pin_num   GPIO引脚编号
 * @param pin_info  输出的引脚信息
 * @return result_e 获取结果, RESULT_STATUS_OK为成功, 其他为失败
 */
static result_e snf_drv_gpio_get_pin_info(uint32_t pin_num, snf_gpio_pin_info_t *pin_info)
{
    if (pin_info == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 初始化输出参数 */
    pin_info->port  = NULL;
    pin_info->pin   = 0;
    pin_info->valid = false;

    /* 检查引脚编号范围 */
    if (!snf_drv_gpio_is_valid_pin_num(pin_num)) {
        return RESULT_STATUS_GPIO_PIN_ERROR;
    }

    /* 计算端口和引脚 */
    uint32_t port_index = pin_num / PORT_PIN_MAX_SIZE;
    uint32_t pin_index  = pin_num % PORT_PIN_MAX_SIZE;

    /* 检查端口索引 */
    if (port_index >= GPIO_PORT_MAX_COUNT) {
        return RESULT_STATUS_GPIO_PORT_ERROR;
    }

    /* 检查引脚索引 */
    if (pin_index >= PORT_PIN_MAX_SIZE) {
        return RESULT_STATUS_GPIO_PIN_ERROR;
    }

    /* 设置引脚信息 */
    pin_info->port  = (GPIO_Type *)gpio_port_table[port_index];
    pin_info->pin   = pin_index;
    pin_info->valid = true;

    return RESULT_STATUS_OK;
}

/**
 * @brief 验证GPIO配置参数
 *
 * @param config GPIO配置
 * @return result_e 验证结果, RESULT_STATUS_OK为成功, 其他为失败
 */
static result_e snf_drv_gpio_validate_config(const snf_gpio_config_t *config)
{
    if (config == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 检查引脚编号 */
    if (!snf_drv_gpio_is_valid_pin_num(config->pin_num)) {
        return RESULT_STATUS_GPIO_PIN_ERROR;
    }

    /* 检查枚举值范围 */
    if (config->mode > DRV_GPIO_PIN_MODE_INPUT_PULL_DOWN) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (config->interrupt_config > DRV_GPIO_PIN_INT_BOTH_EDGE) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief  处理GPIO的pin mode配置
 *
 * @param im_pin_config         芯必达的pin mode配置
 * @param user_pin_config       用户的pin mode配置
 * @return result_e             处理结果, RESULT_STATUS_OK为成功, 其他为失败
 */
static result_e snf_drv_gpio_pin_mode_handle(gpio_pin_config_t       *im_pin_config,
                                             const snf_gpio_config_t *user_pin_config)
{
    if (im_pin_config == NULL || user_pin_config == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    switch (user_pin_config->mode) {
    case DRV_GPIO_PIN_MODE_HIZ:    im_pin_config->pinMode = GPIO_PIN_MODE_HIZ; break;
    case DRV_GPIO_PIN_MODE_OUTPUT: im_pin_config->pinMode = GPIO_PIN_MODE_OUTPUT; break;
    case DRV_GPIO_PIN_MODE_INPUT_FLOATING:
        im_pin_config->pinMode    = GPIO_PIN_MODE_INPUT;
        im_pin_config->pullConfig = GPIO_PIN_PULL_FLOATING;
        break;
    case DRV_GPIO_PIN_MODE_INPUT_PULL_UP:
        im_pin_config->pinMode    = GPIO_PIN_MODE_INPUT;
        im_pin_config->pullConfig = GPIO_PIN_PULL_UP;
        break;
    case DRV_GPIO_PIN_MODE_INPUT_PULL_DOWN:
        im_pin_config->pinMode    = GPIO_PIN_MODE_INPUT;
        im_pin_config->pullConfig = GPIO_PIN_PULL_DOWN;
        break;
    default: return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}
